#include "SimpleTLV.h"

#if defined WIN32
    #include <Winsock2.h>
#else
    #include <arpa/inet.h> 
#endif


uint16_t CSimpleTLV::getLength()
{
    return m_tlv.len;
}
uint16_t CSimpleTLV::encode(uint8_t* buffer, uint16_t length)
{
    if (length < m_tlv.len)
    {
        return 0;
    }

    uint8_t* pos = buffer;
    *reinterpret_cast<uint16_t*>(pos) = htons(m_tlv.tag);
    pos += sizeof(uint16_t);
    *reinterpret_cast<uint16_t*>(pos) = htons(m_tlv.len);
    pos += sizeof(uint16_t);

    switch(m_tlv.val.type)
    {
    case TLV_INT32: 
        *reinterpret_cast<int32_t*>(pos) = htonl(m_tlv.val.iValue);
        break;
    case TLV_UINT32: 
        *reinterpret_cast<uint32_t*>(pos) = htonl(m_tlv.val.uiValue);
        break;
    case TLV_INT64: 
        *reinterpret_cast<int64_t*>(pos) = htonll(m_tlv.val.llValue);
        break;
    case TLV_UINT64: 
        *reinterpret_cast<uint64_t*>(pos) = htonll(m_tlv.val.ullValue);
        break;
    case TLV_FLOAT: 
        *reinterpret_cast<float_t*>(pos) = m_tlv.val.fValue;
        break;
    case TLV_DOUBLE: 
        *reinterpret_cast<double_t*>(pos) = m_tlv.val.dValue;
        break;
    case TLV_OCTSTRING: 
        memcpy(pos, m_tlv.val.pValue, m_tlv.val.iValue);
        break;
    }

    return (m_tlv.len+3)/4*4;
}

//CSimpleTLV
void CSimpleTLV::setTag(uint16_t tag, const uint8_t* value, uint16_t length)
{
    m_tlv.tag = tag;
    m_tlv.len = TLV_HEAD_LEN + length;

    delete m_tlv.val.pValue;
    m_tlv.val.pValue = new uint8_t[length];
    memcpy(m_tlv.val.pValue, value, length);
    m_tlv.val.iValue = length;

    m_tlv.val.type = TLV_OCTSTRING;
}

void CSimpleTLV::setTag(uint16_t tag, int32_t  value)
{
    m_tlv.tag = tag;
    m_tlv.len = TLV_HEAD_LEN + sizeof(value);
    m_tlv.val.iValue = value;
    m_tlv.val.type = TLV_INT32;
}

void CSimpleTLV::setTag(uint16_t tag, int64_t  value)
{
    m_tlv.tag = tag;
    m_tlv.len = TLV_HEAD_LEN + sizeof(value);
    m_tlv.val.llValue = value;
    m_tlv.val.type = TLV_INT64;
}

void CSimpleTLV::setTag(uint16_t tag, uint32_t value)
{
    m_tlv.tag = tag;
    m_tlv.len = TLV_HEAD_LEN + sizeof(value);
    m_tlv.val.uiValue = value;
    m_tlv.val.type = TLV_UINT32;
}

void CSimpleTLV::setTag(uint16_t tag, uint64_t value)
{
    m_tlv.tag = tag;
    m_tlv.len = TLV_HEAD_LEN + sizeof(value);
    m_tlv.val.ullValue = value;
    m_tlv.val.type = TLV_UINT64;
}

void CSimpleTLV::setTag(uint16_t tag, float_t  value)
{
    m_tlv.tag = tag;
    m_tlv.len = TLV_HEAD_LEN + sizeof(value);
    m_tlv.val.fValue = value;
    m_tlv.val.type = TLV_FLOAT;
}

void CSimpleTLV::setTag(uint16_t tag, double_t value)
{
    m_tlv.tag = tag;
    m_tlv.len = TLV_HEAD_LEN + sizeof(value);
    m_tlv.val.dValue = value;
    m_tlv.val.type = TLV_DOUBLE;
}
